use crate::{
    bootstrap::AppState,
    entities::{self, album},
    router::resp,
};

use axum::{
    body::Body,
    extract::{Path, State},
    http::{Response, StatusCode},
    response::IntoResponse,
    Json,
};
use serde_json::json;

use chrono::NaiveDateTime;
use sea_orm::{ActiveValue, EntityTrait, PaginatorTrait};
use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize)]
pub struct AlbumModel {
    pub id: Option<String>,
    pub name: String,
    pub description: Option<String>,
    pub create_ts: Option<NaiveDateTime>,
    pub update_ts: Option<NaiveDateTime>,
    pub owner: Option<i32>,
}

pub async fn new(State(state): State<AppState>, Json(model): Json<AlbumModel>) -> Response<Body> {
    let _album = entities::album::ActiveModel {
        name: ActiveValue::Set(model.name),
        description: ActiveValue::Set(model.description),
        ..Default::default()
    };

    let exec_result = entities::album::Entity::insert(_album)
        .exec_with_returning(&state.db_pool)
        .await;

    println!("{:?}", exec_result);

    match exec_result {
        Ok(res) => {
            tracing::info!("Create Album success ! Album id is {}", res.id);
            resp::RespVO::<()>::success_without_data(format!(
                "Create Album success ! Album id is {}",
                res.id
            ))
            .into_response()
        }
        Err(err) => {
            tracing::error!("{}", err);
            resp::RespVO::<()>::from_error(
                Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()),
                err.to_string(),
                None,
            )
            .into_response()
        }
    }
}

pub async fn update(
    State(state): State<AppState>,
    Path(id): Path<String>,
    Json(model): Json<AlbumModel>,
) -> Response<Body> {
    let _album = entities::album::ActiveModel {
        id: ActiveValue::Set(id),
        name: ActiveValue::Set(model.name),
        description: ActiveValue::Set(model.description),
        update_ts: ActiveValue::Set(Some(chrono::Local::now().naive_utc())),
        ..Default::default()
    };

    let exec_result = entities::album::Entity::update(_album)
        .exec(&state.db_pool)
        .await;

    match exec_result {
        Ok(model) => resp::RespVO::success("succ".to_owned(), Some(model)).into_response(),
        Err(err) => {
            tracing::error!("{}", err);
            resp::RespVO::<()>::from_error(
                Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()),
                err.to_string(),
                None,
            )
            .into_response()
        }
    }
}

pub async fn delete(State(state): State<AppState>, Path(id): Path<String>) -> Response<Body> {
    let exec_result = entities::album::Entity::delete_by_id(id.clone())
        .exec(&state.db_pool)
        .await;

    match exec_result {
        Ok(result) => resp::RespVO::success(
            format!("delete {:?} rows", result.rows_affected),
            Some(json!({
                "rows": result.rows_affected,
                "id": id
            })),
        )
        .into_response(),
        Err(err) => resp::RespVO::<()>::from_error(
            Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()),
            err.to_string(),
            None,
        )
        .into_response(),
    }
}

pub async fn list(State(state): State<AppState>) -> Response<Body> {
    let _id = "0000000000";
    let get_result: Result<Option<entities::album::Model>, sea_orm::DbErr> =
        entities::album::Entity::find_by_id(_id)
            .one(&state.db_pool)
            .await;

    match get_result {
        Ok(data_model) => {
            resp::RespVO::success("succ".to_owned(), Some(data_model)).into_response()
        }
        Err(err) => resp::RespVO::<()>::from_error(
            Some(StatusCode::INTERNAL_SERVER_ERROR.as_u16()),
            err.to_string(),
            None,
        )
        .into_response(),
    }
}

pub async fn bind() {}
